/*
* Copyright (c) Microsoft Corporation.  All Rights Reserved.
*
* Traits classes used for producing parameter values in string representation
*/
#pragma once
#include "Mock10.h"
#include "ParameterValue.h"
#include "WexTypes.h"

namespace Mock10
{
    // These definitions allow you to customize parameter formatting for common types
    #if !defined(LONG_PARAMETER_FORMATTING)
        #define LONG_PARAMETER_FORMATTING L"%x"  // Default to formatting for HRESULTS
    #endif

    #if !defined(INT_PARAMETER_FORMATTING)
        #define INT_PARAMETER_FORMATTING L"%d"
    #endif

    #if !defined(CHAR_PARAMETER_FORMATTING)
        #define CHAR_PARAMETER_FORMATTING L"%c"
    #endif

    #if !defined(SHORT_PARAMETER_FORMATTING)
        #define SHORT_PARAMETER_FORMATTING INT_PARAMETER_FORMATTING
    #endif

    #if !defined(FLOAT_PARAMETER_FORMATTING)
        #define FLOAT_PARAMETER_FORMATTING L"%fl"
    #endif

    #if !defined(SIZE_T_PARAMETER_FORMATTING)
        #if defined(_M_IX86)
            #define SIZE_T_PARAMETER_FORMATTING L"%u"
        #else
            #define SIZE_T_PARAMETER_FORMATTING L"%I64u"
        #endif
    #endif

    #if !defined(DOUBLE_PARAMETER_FORMATTING)
        #define DOUBLE_PARAMETER_FORMATTING FLOAT_PARAMETER_FORMATTING
    #endif

    #if !defined(UNSIGNED_LONG_PARAMETER_FORMATTING)
        #define UNSIGNED_LONG_PARAMETER_FORMATTING L"%u"
    #endif

    #if !defined(UNSIGNED_INT_PARAMETER_FORMATTING)
        #define UNSIGNED_INT_PARAMETER_FORMATTING UNSIGNED_LONG_PARAMETER_FORMATTING
    #endif

    #if !defined(UNSIGNED_CHAR_PARAMETER_FORMATTING)
        #define UNSIGNED_CHAR_PARAMETER_FORMATTING UNSIGNED_INT_PARAMETER_FORMATTING
    #endif

    #if !defined(UNSIGNED_SHORT_PARAMETER_FORMATTING)
        #define UNSIGNED_SHORT_PARAMETER_FORMATTING UNSIGNED_INT_PARAMETER_FORMATTING
    #endif

    #if !defined(INT_64_PARAMETER_FORMATTING)
        #define INT_64_PARAMETER_FORMATTING L"%I64d"
    #endif

    #if !defined(UNSIGNED_INT_64_PARAMETER_FORMATTING)
        #define UNSIGNED_INT_64_PARAMETER_FORMATTING L"%I64u"
    #endif

    #if !defined(POINTER_PARAMETER_FORMATTING)
        #define POINTER_PARAMETER_FORMATTING L"%p"  
    #endif

    #if !defined(WCHAR_T_PARAMETER_FORMATTING)
        #define WCHAR_T_PARAMETER_FORMATTING L"%s"  
    #endif

    #if !defined(CHAR_PTR_PARAMETER_FORMATTING)
        #define CHAR_PTR_PARAMETER_FORMATTING L"%S"  
    #endif

    // Users can create custom ParameterValueTrait implementations for their classes to provide custom value-to-string conversions
    template <typename T>
    class ParameterValueTrait
    {
    public:
        // Default implementation just return empty value
        static ParameterValue GetValue(const T&)
        {
            return ParameterValue();
        }
    };

    template <typename T>
    class ParameterValueTrait<T&>
    {
    public:
        static ParameterValue GetValue(const T& ref)
        {
            // Default implementation call through to non reference type
            return ParameterValueTrait<T>::GetValue(ref);
        }
    };

    template <typename T>
    class ParameterValueTrait<T*>
    {
    public:
        static ParameterValue GetValue(T* const& p)
        {
            ParameterValue value;
            if (value.IsValid())
            {
                value.Format(POINTER_PARAMETER_FORMATTING, p);
            }
            return value;                                                
        }
    };

    template <typename T>
    class ParameterValueTrait<const T*>
    {
    public:
        static ParameterValue GetValue(const T* const& p)
        {
            return ParameterValueTrait<WEX::Common::RemoveConst<T>::Type*>::GetValue(const_cast<T* const&>(p));
        }
    };

    template <>
    class ParameterValueTrait<bool>
    {
    public:
        static ParameterValue GetValue(const bool& value)
        {
            return (value ? ParameterValue(L"true") : ParameterValue(L"false"));                                                
        }
    };

    #define BUILD_PARAMETER_TRAIT(__type, __formatString)                                                    \
        template<>                                                                                           \
        class ParameterValueTrait<__type>                                                                    \
        {                                                                                                    \
        public:                                                                                              \
            static ParameterValue GetValue(__type const& __val)                                              \
            {                                                                                                \
                ParameterValue value;                                                                        \
                if (value.IsValid())                                                                         \
                {                                                                                            \
                    value.Format(__formatString, __val);                                                     \
                }                                                                                            \
                return value;                                                                                \
            }                                                                                                \
        };                                                                                                  

    BUILD_PARAMETER_TRAIT(long, LONG_PARAMETER_FORMATTING); 
    BUILD_PARAMETER_TRAIT(int, INT_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(char, CHAR_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(short, SHORT_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(float, FLOAT_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(double, DOUBLE_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(unsigned long, UNSIGNED_LONG_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(unsigned int, UNSIGNED_INT_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(unsigned char, UNSIGNED_CHAR_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(unsigned short, UNSIGNED_SHORT_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(__int64, INT_64_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(unsigned __int64, UNSIGNED_INT_64_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(wchar_t*, WCHAR_T_PARAMETER_FORMATTING);
    BUILD_PARAMETER_TRAIT(char*, CHAR_PTR_PARAMETER_FORMATTING);

    #undef BUILD_PARAMETER_TRAIT
} /* namespace Mock10 */
